package list

import (
	"errors"
	"fanshuai-go/common"
	"strconv"
)

type ArrayList struct {
	array []interface{}
}

func NewArrayList(size int) *ArrayList {
	return &ArrayList{array: make([]interface{}, 0, size)}
}

func (a *ArrayList) Size() int {
	return len(a.array)
}

func (a *ArrayList) IsEmpty() bool {
	return len(a.array) == 0
}

func (a *ArrayList) Capacity() int {
	return cap(a.array)
}

func (a *ArrayList) Add(data interface{}) {
	a.array = append(a.array, data)
}

func (a *ArrayList) AddIndex(index int, data interface{}) {
	size := len(a.array)
	if index < 0 || index > size {
		panic(errors.New("index out of bounds, index=" + strconv.Itoa(index)))
	}

	var newArray = make([]interface{}, 0, size+1)

	if index > 0 {
		newArray = append(newArray, a.array[0:index-1])
	}
	newArray = append(newArray, data)
	if index < size {
		newArray = append(newArray, a.array[index:])
	}

	a.array = newArray
}

func (a *ArrayList) Remove(data interface{}) {
	index := -1

	for i := 0; i < len(a.array); i++ {
		if a.array[i] == data {
			index = i
			a.RemoveIndex(index)
		}
	}
}

func (a *ArrayList) RemoveIndex(index int) {
	size := len(a.array)
	if index < 0 || index > size {
		panic(errors.New("index out of bounds, index=" + strconv.Itoa(index)))
	}

	var newArray = make([]interface{}, 0, size-1)

	if index > 0 {
		newArray = append(newArray, a.array[0:index-1])
	}
	if index < size {
		newArray = append(newArray, a.array[index+1:])
	}
	a.array = newArray
}

func (a *ArrayList) Get(index int) interface{} {
	size := len(a.array)
	if index < 0 || index > size {
		panic(errors.New("index out of bounds, index=" + strconv.Itoa(index)))
	}

	return a.array[index]
}

func (a *ArrayList) IndexOf(i interface{}) int {
	for i := 0; i < len(a.array); i++ {
		if a.array[i] == i {
			return i
		}
	}

	return -1
}

func (a *ArrayList) AddAll(list List) {
	iterator := a.Iterator()
	for iterator.HasNext() {
		data := iterator.Next()

		a.Add(data)
	}
}

func (a *ArrayList) Clear() {
	a.array = nil
}

func (a *ArrayList) Iterator() common.Iterator {
	return &ArrayListIterator{index: 0, list: a}
}

type ArrayListIterator struct {
	index int
	list  *ArrayList
}

func (a *ArrayListIterator) HasNext() bool {
	return a.index < len(a.list.array)
}

func (a *ArrayListIterator) Next() interface{} {
	data := a.list.array[a.index]
	a.index++
	return data
}
